<template>
  <div class="report-detail-container">
    <div
      class="content-wrapper"
      v-loading="loading"
      element-loading-text="正在加载性能报告详情..."
    >
      <div v-if="loading" style="min-height: 200px"></div>
      <div v-else-if="error" class="error-message">
        {{ error }}
        <el-button
          @click="fetchReportDetail"
          type="danger"
          size="small"
          style="margin-left: 10px"
        >
          重试
        </el-button>
      </div>
      <div v-else>
        <div class="report-header">
          <el-button @click="goBack" type="default" class="back-btn">
            <template #icon>
              <SvgIcon name="arrow-left" size="16px" />
            </template>
            返回
          </el-button>
          <div class="title-container">
            <h1 class="report-title">性能测试报告详情</h1>
            <div class="report-id-container">
              <span class="report-id">{{ reportId }}</span>
              <el-button
                @click="copyToClipboard(reportId, '报告ID')"
                size="small"
                text
                title="复制报告ID"
              >
                <template #icon>
                  <SvgIcon name="copy" size="14px" />
                </template>
              </el-button>
            </div>
          </div>
        </div>

        <!-- 内存趋势（可缩放/可筛选） -->
        <div class="section">
          <div class="section-header">
            <h3 class="section-title">内存趋势</h3>
          </div>
          <el-card shadow="hover">
            <div class="memory-chart" ref="memoryChartRef"></div>
            <div class="memory-legend">
              <div
                v-for="name in memoryMetricKeys"
                :key="name"
                class="memory-legend-item"
                :class="{ inactive: memoryLegendSelected[name] === false }"
              >
                <span
                  class="legend-dot"
                  role="button"
                  tabindex="0"
                  :aria-pressed="memoryLegendSelected[name] !== false"
                  :style="{
                    backgroundColor:
                      memoryLegendSelected[name] === false
                        ? '#dcdfe6'
                        : memoryLegendColors[name] || '#909399',
                  }"
                  @click.stop="toggleLegend(name)"
                  @keydown.enter.prevent="toggleLegend(name)"
                  @keydown.space.prevent="toggleLegend(name)"
                ></span>
                <span class="legend-name" @click.stop>{{ name }}</span>
                <span class="legend-avg" @click.stop>
                  平均值：{{ formatValue(name, memoryAverages[name]) }}
                </span>
                <span class="legend-max" @click.stop>
                  最大值：{{ formatValue(name, memoryMaximums[name]) }}
                </span>
                <span class="legend-min" @click.stop>
                  最小值：{{ formatValue(name, memoryMinimums[name]) }}
                </span>
              </div>
            </div>
          </el-card>
        </div>

        <div class="section">
          <div class="section-header">
            <h3 class="section-title">崩溃信息</h3>
            <div
              class="download-actions"
              v-if="reportDetail.crashes && reportDetail.crashes.length > 0"
            >
              <el-button @click="remoteConnect" type="primary" size="small">
                <template #icon>
                  <SvgIcon name="connection" size="14px" />
                </template>
                远程连接
              </el-button>
              <el-button @click="downloadLog" type="success" size="small">
                <template #icon>
                  <SvgIcon name="download" size="14px" />
                </template>
                下载崩溃日志
              </el-button>
            </div>
          </div>
          <div class="crashes-container">
            <div
              v-if="reportDetail.crashes && reportDetail.crashes.length > 0"
              class="crashes-list"
            >
              <div
                class="crash-item"
                v-for="(crash, index) in reportDetail.crashes"
                :key="index"
              >
                <div class="crash-header">
                  <div class="crash-title">崩溃 #{{ index + 1 }}</div>
                  <div class="crash-time">{{ crash.timestamp }}</div>
                </div>
                <div class="crash-details">
                  <div class="crash-type">{{ crash.type }}</div>
                  <div class="crash-message">{{ crash.message }}</div>
                </div>
                <div class="crash-stack">
                  <pre>{{ crash.stack_trace }}</pre>
                  <pre><span style="color: red;">process_uptime：</span>{{ crash.process_uptime }}</pre>
                  <pre>{{ crash.backtrace }}</pre>
                </div>
              </div>
            </div>
            <div v-else class="no-crashes">
              <div class="no-crashes-icon">✓</div>
              <div class="no-crashes-message">测试过程中未发现崩溃</div>
            </div>
          </div>
        </div>

        <!-- KOOM 高内存警告 -->
        <div class="section">
          <div class="section-header">
            <h3 class="section-title">koom高内存警告</h3>
          </div>
          <el-card shadow="hover">
            <el-table :data="koomWarnings" style="width: 100%" size="small">
              <template #empty>
                <div class="table-empty-success">测试过程中未发现问题</div>
              </template>
              <el-table-column
                prop="created_at"
                label="时间"
                min-width="160"
                align="center"
              />
              <el-table-column
                prop="file_name"
                label="文件名"
                min-width="200"
                show-overflow-tooltip
              />
              <el-table-column
                prop="file_path"
                label="文件路径"
                min-width="260"
                show-overflow-tooltip
              />
              <el-table-column
                prop="report_id"
                label="报告ID"
                min-width="220"
                show-overflow-tooltip
              />
              <el-table-column label="操作" width="100" align="center">
                <template #default="{ row }">
                  <el-button
                    type="primary"
                    link
                    size="small"
                    @click="showKoomDetail(row)"
                  >
                    详情
                  </el-button>
                </template>
              </el-table-column>
            </el-table>
          </el-card>
        </div>

        <!-- KOOM 详情弹窗 -->
        <el-dialog v-model="koomDetailVisible" title="KOOM 详情" width="60%">
          <pre
            style="white-space: pre-wrap; word-break: break-word; margin: 0"
            >{{ formattedKoomDetail }}</pre
          >
        </el-dialog>

        <div class="section" v-if="reportDetail.activity_details">
          <div class="section-header">
            <h3 class="section-title">Activity详情</h3>
          </div>
          <div class="activities-container">
            <div class="activities-columns">
              <el-card class="activities-section" shadow="hover">
                <template #header>
                  <h4 class="activities-subtitle">
                    所有Activity ({{
                      (reportDetail.activity_details?.all_activities || [])
                        .length
                    }})
                  </h4>
                </template>
                <div class="activities-list">
                  <div
                    class="activity-item"
                    v-for="(activity, index) in reportDetail.activity_details
                      ?.all_activities || []"
                    :key="'all-' + index"
                  >
                    {{ activity }}
                  </div>
                  <div
                    v-if="
                      !reportDetail.activity_details?.all_activities?.length
                    "
                    class="empty-message"
                  >
                    没有Activity数据
                  </div>
                </div>
              </el-card>
              <el-card class="activities-section" shadow="hover">
                <template #header>
                  <h4 class="activities-subtitle">
                    已覆盖Activity ({{
                      (reportDetail.activity_details?.explored_activities || [])
                        .length
                    }})
                  </h4>
                </template>
                <div class="activities-list">
                  <div
                    class="activity-item"
                    v-for="(activity, index) in reportDetail.activity_details
                      ?.explored_activities || []"
                    :key="'explored-' + index"
                  >
                    {{ activity }}
                  </div>
                  <div
                    v-if="
                      !reportDetail.activity_details?.explored_activities
                        ?.length
                    "
                    class="empty-message"
                  >
                    没有已覆盖的Activity
                  </div>
                </div>
              </el-card>
            </div>
          </div>
        </div>

        <!-- 崩溃信息 moved above Activity详情 -->

        <!-- 基本信息（移至底部） -->
        <div class="section">
          <div class="section-header">
            <h3 class="section-title">基本信息</h3>
          </div>
          <div class="basic-info-layout">
            <el-card class="info-card primary-info" shadow="hover">
              <template #header>
                <div class="card-header">
                  <div class="card-icon test-icon">📊</div>
                  <div class="card-title">测试概览</div>
                </div>
              </template>
              <div class="card-content">
                <div class="info-row">
                  <label>报告ID:</label>
                  <div class="info-value-container">
                    <span class="info-value">{{ reportId }}</span>
                    <el-button
                      @click="copyToClipboard(reportId, '报告ID')"
                      size="small"
                      text
                      title="复制报告ID"
                    >
                      <template #icon>
                        <SvgIcon name="copy" size="14px" />
                      </template>
                    </el-button>
                  </div>
                </div>
                <div class="info-row">
                  <label>测试时长:</label>
                  <span class="info-value highlight">
                    {{ reportDetail.test_summary?.duration_minutes || 0 }}分钟
                  </span>
                </div>
                <div class="info-row">
                  <label>测试开始时间:</label>
                  <span class="info-value">
                    {{
                      reportDetail.test_summary?.basic_info?.start_time || ''
                    }}
                  </span>
                </div>
                <div class="info-row">
                  <label>测试UUID:</label>
                  <span class="info-value uuid">
                    {{ reportDetail.test_summary?.basic_info?.uuid || '' }}
                  </span>
                </div>
              </div>
            </el-card>

            <el-card class="info-card app-info" shadow="hover">
              <template #header>
                <div class="card-header">
                  <div class="card-icon app-icon">📱</div>
                  <div class="card-title">应用信息</div>
                </div>
              </template>
              <div class="card-content">
                <div class="info-row">
                  <label>应用包名:</label>
                  <div class="info-value-container">
                    <span class="info-value package">
                      {{ reportDetail.test_summary?.basic_info?.package || '' }}
                    </span>
                    <el-button
                      v-if="reportDetail.test_summary?.basic_info?.package"
                      @click="
                        copyToClipboard(
                          reportDetail.test_summary?.basic_info?.package,
                          '应用包名',
                        )
                      "
                      size="small"
                      text
                      title="复制应用包名"
                    >
                      <template #icon>
                        <SvgIcon name="copy" size="14px" />
                      </template>
                    </el-button>
                  </div>
                </div>
                <div class="info-row">
                  <label>应用版本:</label>
                  <div class="info-value-container">
                    <span class="info-value version">
                      {{ reportDetail.test_summary?.basic_info?.version || '' }}
                    </span>
                    <el-button
                      v-if="reportDetail.test_summary?.basic_info?.version"
                      @click="
                        copyToClipboard(
                          reportDetail.test_summary?.basic_info?.version,
                          '应用版本',
                        )
                      "
                      size="small"
                      text
                      title="复制应用版本"
                    >
                      <template #icon>
                        <SvgIcon name="copy" size="14px" />
                      </template>
                    </el-button>
                  </div>
                </div>
              </div>
            </el-card>

            <el-card class="info-card device-info" shadow="hover">
              <template #header>
                <div class="card-header">
                  <div class="card-icon device-icon">📲</div>
                  <div class="card-title">设备信息</div>
                </div>
              </template>
              <div class="card-content">
                <div class="info-row">
                  <label>设备ID:</label>
                  <div class="info-value-container">
                    <span class="info-value">
                      {{
                        reportDetail.test_summary?.basic_info?.device_id || ''
                      }}
                    </span>
                    <el-button
                      v-if="reportDetail.test_summary?.basic_info?.device_id"
                      @click="
                        copyToClipboard(
                          reportDetail.test_summary?.basic_info?.device_id,
                          '设备ID',
                        )
                      "
                      size="small"
                      text
                      title="复制设备ID"
                    >
                      <template #icon>
                        <SvgIcon name="copy" size="14px" />
                      </template>
                    </el-button>
                  </div>
                </div>
                <div class="info-row">
                  <label>设备型号:</label>
                  <span class="info-value">
                    {{ reportDetail.test_summary?.basic_info?.device || '' }}
                  </span>
                </div>
                <div class="info-row">
                  <label>设备序列号:</label>
                  <span class="info-value serial">
                    {{ reportDetail.test_summary?.basic_info?.serial || '' }}
                  </span>
                </div>
              </div>
            </el-card>
          </div>
        </div>

        <!-- 覆盖率信息（移至底部） -->
        <div class="section">
          <div class="section-header">
            <h3 class="section-title">覆盖率信息</h3>
          </div>
          <div class="coverage-layout">
            <el-card class="coverage-chart-container" shadow="hover">
              <template #header>
                <div class="chart-title">Activity覆盖率</div>
              </template>
              <div class="coverage-chart">
                <div class="pie-chart-container">
                  <div class="pie-chart" :style="pieChartStyle">
                    <div class="pie-chart-center">
                      <div class="percentage">
                        {{
                          (
                            reportDetail.coverage_metrics
                              ?.coverage_percentage || 0
                          ).toFixed(1)
                        }}%
                      </div>
                      <div class="label">覆盖率</div>
                    </div>
                  </div>
                </div>
                <div class="chart-legend">
                  <div class="legend-item">
                    <div class="legend-color covered"></div>
                    <span>
                      已覆盖 ({{
                        reportDetail.coverage_metrics?.explored_activities || 0
                      }})
                    </span>
                  </div>
                  <div class="legend-item">
                    <div class="legend-color uncovered"></div>
                    <span>
                      未覆盖 ({{
                        (reportDetail.coverage_metrics?.total_activities || 0) -
                        (reportDetail.coverage_metrics?.explored_activities ||
                          0)
                      }})
                    </span>
                  </div>
                </div>
              </div>
            </el-card>

            <div class="coverage-stats-container">
              <el-card class="coverage-stat-card" shadow="hover">
                <div class="stat-content">
                  <div class="stat-top-row">
                    <div class="stat-icon">🎯</div>
                    <div class="stat-value">
                      {{ reportDetail.coverage_metrics?.total_activities || 0 }}
                    </div>
                  </div>
                  <div class="stat-label">总Activity数</div>
                </div>
              </el-card>

              <el-card class="coverage-stat-card" shadow="hover">
                <div class="stat-content">
                  <div class="stat-top-row">
                    <div class="stat-icon">✅</div>
                    <div class="stat-value">
                      {{
                        reportDetail.coverage_metrics?.explored_activities || 0
                      }}
                    </div>
                  </div>
                  <div class="stat-label">已覆盖Activity</div>
                </div>
              </el-card>

              <el-card class="coverage-stat-card" shadow="hover">
                <div class="stat-content">
                  <div class="stat-top-row">
                    <div class="stat-icon">📈</div>
                    <div class="stat-value">
                      {{
                        (
                          reportDetail.coverage_metrics?.coverage_percentage ||
                          0
                        ).toFixed(2)
                      }}%
                    </div>
                  </div>
                  <div class="stat-label">覆盖率</div>
                </div>
              </el-card>
            </div>
          </div>
        </div>

        <!-- 事件统计（移至底部） -->
        <div class="section">
          <div class="section-header">
            <h3 class="section-title">事件统计</h3>
          </div>
          <div class="events-grid">
            <el-card class="event-total" shadow="hover">
              <div class="event-total-label">总事件数</div>
              <div class="event-total-value">
                {{ reportDetail.event_statistics?.total_events || 0 }}
              </div>
            </el-card>
            <el-card
              v-for="(count, type) in reportDetail.event_statistics
                ?.event_types || {}"
              :key="type"
              class="event-item"
              shadow="hover"
            >
              <div class="event-count">{{ count || 0 }}</div>
              <div class="event-label">{{ formatEventType(type) }}</div>
              <div class="event-percentage">
                {{ calculateEventPercentage(count).toFixed(1) }}%
              </div>
            </el-card>
          </div>
        </div>
      </div>
    </div>
    <!-- 设备控制弹窗 -->
    <el-dialog
      v-model="showDeviceControlModal"
      :title="`设备控制 - ${currentDeviceName}`"
      width="50%"
      @close="closeDeviceControlModal"
      :close-on-click-modal="true"
      class="device-control-dialog"
    >
      <template #header="{ titleId, titleClass }">
        <div class="dialog-header">
          <span :id="titleId" :class="titleClass">
            设备控制 - {{ currentDeviceName }}
          </span>
          <el-button
            @click="refreshIframe"
            size="small"
            style="margin-right: 8px"
          >
            <template #icon>
              <SvgIcon name="reload" size="14px" />
            </template>
            刷新
          </el-button>
        </div>
      </template>
      <div class="device-control-container">
        <iframe
          :src="currentDeviceUrl"
          frameborder="0"
          class="device-control-frame"
          ref="deviceControlFrame"
        ></iframe>
      </div>
    </el-dialog>
  </div>
</template>

<script>
/* eslint-disable vue/no-unused-components */

import request from '@/utils/request'
import SvgIcon from '@/views/components/SvgIcon.vue'

export default {
  name: 'ReportDetailViewV2',
  components: {
    SvgIcon,
  },
  data() {
    return {
      reportId: null,
      report: null,
      loading: false,
      error: null,
      showDeviceControlModal: false,
      currentDeviceName: '',
      currentDeviceUrl: '',
      memoryChart: null,
      // 内存图例相关
      memoryMetricKeys: [
        'fdCount',
        'threadCount',
        'maxMemory',
        'totalMemory',
        'freeMemory',
        'javaHeapMemoryPss',
        'nativeHeapMemoryPss',
        'totalPss',
        'nativeHeapSize',
        'nativeHeapAllocatedSize',
        'nativeHeapFreeSize',
      ],
      memoryCountKeys: ['fdCount', 'threadCount'],
      memoryLegendSelected: {},
      memoryLegendColors: {},
      memoryAverages: {},
      memoryMaximums: {},
      memoryMinimums: {},
      // KOOM 高内存预警数据占位
      koomWarnings: [],
      koomDetailVisible: false,
      koomDetailRaw: null,
    }
  },
  computed: {
    reportDetail() {
      return this.report || {}
    },
    pieChartStyle() {
      const percentage =
        this.reportDetail.coverage_metrics?.coverage_percentage || 0
      const angle = (percentage / 100) * 360

      if (percentage <= 50) {
        return {
          background: `conic-gradient(#42b983 0deg ${angle}deg, #e4e7ed ${angle}deg 360deg)`,
        }
      } else {
        return {
          background: `conic-gradient(#42b983 0deg ${angle}deg, #e4e7ed ${angle}deg 360deg)`,
        }
      }
    },
    formattedKoomDetail() {
      try {
        return typeof this.koomDetailRaw === 'string'
          ? this.koomDetailRaw
          : JSON.stringify(this.koomDetailRaw, null, 2)
      } catch (e) {
        return String(this.koomDetailRaw || '')
      }
    },
  },
  methods: {
    async fetchReportDetail() {
      this.loading = true
      this.error = null
      try {
        const response = await request.post(`/fastbot/report/${this.reportId}`)
        this.report = response.data
        await this.fetchMemoryInfo()
        this.computeMemoryAverages()
        await this.fetchKoomWarnings()
        this.$nextTick(() => {
          this.renderMemoryChart()
        })
      } catch (error) {
        this.error = '获取报告详情失败，请刷新页面重试'
      } finally {
        this.loading = false
      }
    },
    // 获取 KOOM 高内存预警数据
    async fetchKoomWarnings() {
      try {
        const resp = await request.get('/performance/memory_leak_info/query', {
          params: { report_id: this.reportId },
        })
        const payload = resp?.data ?? resp
        const list = Array.isArray(payload?.data?.datalist)
          ? payload.data.datalist
          : Array.isArray(payload?.datalist)
          ? payload.datalist
          : []

        this.koomWarnings = list.map((item) => {
          let parsed = null
          try {
            parsed = item.leak_report ? JSON.parse(item.leak_report) : null
          } catch (e) {
            parsed = null
          }

          const classInfos = Array.isArray(parsed?.classInfos)
            ? parsed.classInfos
            : []
          const reason =
            classInfos.length > 0
              ? classInfos
                  .slice(0, 3)
                  .map((c) =>
                    [c.className, c.instanceCount].filter(Boolean).join(' x '),
                  )
                  .join(', ')
              : '疑似内存泄漏'

          return {
            id: item.id,
            report_id: item.report_id,
            file_name: item.file_name,
            file_path: item.file_path,
            created_at: item.created_at,
            leak_report: item.leak_report,
            reason,
            _parsed: parsed,
            _raw: item,
          }
        })
      } catch (e) {
        console.warn('获取 KOOM 预警失败', e)
        this.koomWarnings = []
      }
    },
    showKoomDetail(row) {
      try {
        this.koomDetailRaw = row.leak_report
          ? JSON.parse(row.leak_report)
          : row._parsed || row.leak_report
      } catch (e) {
        this.koomDetailRaw = row.leak_report || row._parsed || row
      }
      this.koomDetailVisible = true
    },
    // 获取内存信息数据
    async fetchMemoryInfo() {
      try {
        const resp = await request.get('/performance/memory_info/query', {
          params: { report_id: this.reportId },
        })
        const payload = resp?.data ?? resp

        let rows = []
        if (Array.isArray(payload)) {
          rows = payload
        } else if (Array.isArray(payload?.data)) {
          rows = payload.data
        } else if (Array.isArray(payload?.data?.datalist)) {
          rows = payload.data.datalist
        } else if (Array.isArray(payload?.datalist)) {
          rows = payload.datalist
        } else if (Array.isArray(payload?.records)) {
          rows = payload.records
        } else if (Array.isArray(payload?.memory_info_list)) {
          rows = payload.memory_info_list
        } else if (payload?.memory_info) {
          rows = [payload.memory_info]
        } else if (payload?.result) {
          rows = Array.isArray(payload.result)
            ? payload.result
            : [payload.result]
        }

        if (!this.report) this.report = {}
        if (!this.report.performance) this.report.performance = {}
        this.report.performance.memory_info_list = rows
      } catch (e) {
        // 忽略错误，仍允许页面其余部分显示
        console.warn('获取内存信息失败', e)
      }
    },
    // 内存图渲染
    async renderMemoryChart() {
      try {
        // 动态引入 echarts，避免首屏体积过大
        const echartsMod = await import('echarts')
        const echarts = echartsMod.default || echartsMod

        if (!this.memoryChart) {
          const dom = this.$refs.memoryChartRef
          if (!dom) return
          this.memoryChart = echarts.init(dom)
          window.addEventListener('resize', this.handleResize, {
            passive: true,
          })
        }

        const { seriesDefs } = this.buildMemorySeries()

        // 初始化图例选中状态与颜色
        if (
          !this.memoryLegendSelected ||
          Object.keys(this.memoryLegendSelected).length === 0
        ) {
          this.initMemoryLegend()
        }

        // 依据最新数据更新平均值
        this.computeMemoryAverages()

        const option = {
          tooltip: {
            trigger: 'axis',
            confine: true,
            axisPointer: { type: 'cross' },
            formatter: (params) => {
              const list = Array.isArray(params) ? params : [params]
              const first = list[0]
              const timeLabel = first?.axisValueLabel || first?.axisValue || ''
              const rows = list
                .filter(
                  (p) => this.memoryLegendSelected?.[p.seriesName] !== false,
                )
                .map((p) => {
                  const color =
                    p.color ||
                    this.memoryLegendColors[p.seriesName] ||
                    '#909399'
                  const rawVal = Array.isArray(p.data) ? p.data[1] : p.value
                  const displayVal =
                    rawVal == null || isNaN(rawVal)
                      ? '-'
                      : `${Number(rawVal).toFixed(2)} MB`
                  return `<div style=\"display:flex;align-items:center;gap:6px;margin:2px 0;\">\n                    <span style=\"display:inline-block;width:8px;height:8px;border-radius:50%;background:${color}\"></span>\n                    <span style=\"flex:1;min-width:120px;color:#606266;\">${p.seriesName}</span>\n                    <b style=\"color:#303133;\">${displayVal}</b>\n                  </div>`
                })
                .join('')
              return `<div style=\"min-width:220px;max-width:360px;\">\n                <div style=\"font-weight:600;color:#303133;margin-bottom:6px;\">${timeLabel}</div>\n                ${rows}\n              </div>`
            },
          },
          legend: {
            type: 'plain',
            orient: 'horizontal',
            selectedMode: true,
            bottom: 50,
            left: 10,
            right: 10,
            itemWidth: 12,
            itemHeight: 8,
            itemGap: 12,
            textStyle: { fontSize: 11 },
            z: 3,
            selected: this.memoryLegendSelected,
          },
          toolbox: {
            right: 10,
            feature: {
              restore: {},
              saveAsImage: {},
            },
          },
          grid: { left: 40, right: 20, top: 30, bottom: 180 },
          xAxis: {
            type: 'time',
            boundaryGap: false,
            axisLabel: {
              formatter: (value) => {
                const d = new Date(value)
                const pad = (n) => (n < 10 ? `0${n}` : `${n}`)
                return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
                  d.getDate(),
                )}\n${pad(d.getHours())}:${pad(d.getMinutes())}`
              },
            },
          },
          yAxis: {
            type: 'value',
            name: 'MB',
            axisLabel: { formatter: '{value}' },
            splitLine: { show: true },
          },
          dataZoom: [
            { type: 'inside', throttle: 30 },
            {
              type: 'slider',
              height: 22,
              bottom: 10,
              fillerColor: 'rgba(64,158,255,0.15)',
            },
          ],
          series: seriesDefs,
        }

        this.memoryChart.setOption(option, true)
      } catch (e) {
        // 忽略渲染错误，避免打断主流程
        console.error('内存图渲染失败:', e)
      }
    },
    handleResize() {
      if (this.memoryChart) this.memoryChart.resize()
    },
    buildMemorySeries() {
      // 兼容多种字段命名，优先数组
      const candidates = [
        this.report?.memory_series,
        this.report?.memory_info_list,
        this.report?.memory_records,
        this.report?.performance?.memory_info_list,
      ].filter(Boolean)

      let rows = []
      for (const c of candidates) {
        if (Array.isArray(c) && c.length > 0) {
          rows = c
          break
        }
      }
      if (rows.length === 0 && this.report?.memory_info) {
        rows = [this.report.memory_info]
      }

      // 排序（按 time 或 created_at 升序）
      if (Array.isArray(rows) && rows.length > 1) {
        rows = [...rows].sort((a, b) => {
          const ta = new Date(
            a.time || a.timestamp || a.created_at || 0,
          ).getTime()
          const tb = new Date(
            b.time || b.timestamp || b.created_at || 0,
          ).getTime()
          return ta - tb
        })
      }

      // 目标字段（单位转换为 MB）
      const metricKeys = this.memoryMetricKeys

      const toMB = (x) => {
        if (x == null) return null
        // 认为后端以字节为单位，转MB
        return Number(x) / (1024 * 1024)
      }

      // xAxis 为 time 类型时，series 数据点的第一项可直接传 Date 或 可解析的字符串
      const timestamps = rows.map((r) => r.time || r.timestamp || r.created_at)
      const palette = [
        '#FF6B6B',  // 珊瑚红
        '#4ECDC4',  // 青绿色
        '#45B7D1',  // 天蓝色
        '#96CEB4',  // 薄荷绿
        '#FFEAA7',  // 金黄色
        '#DDA0DD',  // 梅红色
        '#98D8C8',  // 海绿色
        '#F7DC6F',  // 柠檬黄
        '#BB8FCE',  // 淡紫色
        '#85C1E9',  // 浅蓝色
        '#F8C471',  // 橙黄色
      ]

      const seriesDefs = metricKeys.map((key, idx) => ({
        name: key,
        type: 'line',
        showSymbol: false,
        smooth: true,
        color: this.memoryLegendColors[key] || palette[idx % palette.length],
        data: rows.map((r) => [
          r.time || r.timestamp || r.created_at,
          this.memoryCountKeys.includes(key)
            ? r[key] == null
              ? null
              : Number(r[key])
            : toMB(r[key]),
        ]),
      }))

      return { timestamps, seriesDefs }
    },
    computeMemoryAverages() {
      try {
        const candidates = [
          this.report?.memory_series,
          this.report?.memory_info_list,
          this.report?.memory_records,
          this.report?.performance?.memory_info_list,
        ].filter(Boolean)

        let rows = []
        for (const c of candidates) {
          if (Array.isArray(c) && c.length > 0) {
            rows = c
            break
          }
        }
        if (rows.length === 0 && this.report?.memory_info) {
          rows = [this.report.memory_info]
        }

        const sums = {}
        const counts = {}
        const maxs = {}
        const mins = {}
        const toMB = (x) => (x == null ? null : Number(x) / (1024 * 1024))
        this.memoryMetricKeys.forEach((k) => {
          sums[k] = 0
          counts[k] = 0
          maxs[k] = Number.NEGATIVE_INFINITY
          mins[k] = Number.POSITIVE_INFINITY
        })
        rows.forEach((r) => {
          this.memoryMetricKeys.forEach((k) => {
            const v = this.memoryCountKeys.includes(k)
              ? r?.[k] == null
                ? null
                : Number(r?.[k])
              : toMB(r?.[k])
            if (v != null && !isNaN(v)) {
              sums[k] += v
              counts[k] += 1
              if (v > maxs[k]) maxs[k] = v
              if (v < mins[k]) mins[k] = v
            }
          })
        })
        const avg = {}
        const maxObj = {}
        const minObj = {}
        this.memoryMetricKeys.forEach((k) => {
          avg[k] = counts[k] > 0 ? sums[k] / counts[k] : null
          maxObj[k] = counts[k] > 0 ? maxs[k] : null
          minObj[k] = counts[k] > 0 ? mins[k] : null
        })
        this.memoryAverages = avg
        this.memoryMaximums = maxObj
        this.memoryMinimums = minObj
      } catch (e) {
        this.memoryAverages = {}
        this.memoryMaximums = {}
        this.memoryMinimums = {}
      }
    },
    initMemoryLegend() {
      const nextSelected = {}
      this.memoryMetricKeys.forEach((k) => {
        nextSelected[k] = true
      })
      const palette = [
        '#FF6B6B',  // 珊瑚红
        '#4ECDC4',  // 青绿色
        '#45B7D1',  // 天蓝色
        '#96CEB4',  // 薄荷绿
        '#FFEAA7',  // 金黄色
        '#DDA0DD',  // 梅红色
        '#98D8C8',  // 海绿色
        '#F7DC6F',  // 柠檬黄
        '#BB8FCE',  // 淡紫色
        '#85C1E9',  // 浅蓝色
        '#F8C471',  // 橙黄色
      ]
      const nextColors = {}
      this.memoryMetricKeys.forEach((k, idx) => {
        nextColors[k] = palette[idx % palette.length]
      })
      this.memoryLegendSelected = nextSelected
      this.memoryLegendColors = nextColors
    },
    toggleLegend(name) {
      const current = this.memoryLegendSelected?.[name]
      const next = {
        ...this.memoryLegendSelected,
        [name]: current === false ? true : false,
      }
      this.memoryLegendSelected = next
      if (this.memoryChart) {
        this.memoryChart.setOption({ legend: { selected: next } }, false)
      }
    },
    formatValue(key, v) {
      if (v == null || isNaN(v)) return '-'
      return this.memoryCountKeys.includes(key)
        ? `${Math.round(v)}`
        : `${v.toFixed(2)} MB`
    },
    formatMB(v) {
      if (v == null || isNaN(v)) return '-'
      return `${v.toFixed(2)} MB`
    },
    goBack() {
      this.$router.push('/performance/automation')
    },
    formatDate(dateString) {
      if (!dateString) return ''
      return dateString.replace(
        /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/,
        '$1-$2-$3 $4:$5',
      )
    },
    formatEventType(type) {
      const typeMap = {
        CLICK: '点击',
        LONG_CLICK: '长按',
        SCROLL_TOP_DOWN: '下滑',
        SCROLL_BOTTOM_UP: '上滑',
        SCROLL_LEFT_RIGHT: '右滑',
        SCROLL_RIGHT_LEFT: '左滑',
        BACK: '返回',
      }
      return typeMap[type] || type
    },
    calculateEventPercentage(count) {
      if (
        !this.report ||
        !this.report.event_statistics ||
        !this.report.event_statistics.total_events
      ) {
        return 0
      }
      return (count / this.report.event_statistics.total_events) * 100
    },
    async downloadLog() {
      try {
        const response = await request.post(
          '/fastbot/crash_log',
          {
            report_id: this.reportId,
          },
          {
            responseType: 'blob',
          },
        )
        const url = window.URL.createObjectURL(new Blob([response]))
        const link = document.createElement('a')
        link.href = url
        link.setAttribute('download', `crash_log_${this.reportId}.txt`)
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
        window.URL.revokeObjectURL(url)
      } catch (error) {
        this.$message.error('下载崩溃日志失败')
      }
    },
    remoteConnect() {
      const deviceId = this.reportDetail.test_summary?.basic_info?.device_id
      if (!deviceId) {
        this.$message.warning('设备ID信息缺失，无法进行远程连接')
        return
      }
      this.navigateToDeviceDetail(deviceId, deviceId)
    },
    navigateToDeviceDetail(deviceId, deviceName) {
      // 使用协议自适应的设备控制配置
      const deviceControlConfig = this.$getDeviceControlConfig('auto')

      const encodedUdid = encodeURIComponent(`${deviceName}`)
      const wsUrl = encodeURIComponent(
        `${deviceControlConfig.wsProtocol}://${deviceControlConfig.wsServer}/?action=proxy-adb&remote=tcp%3A8886&udid=${deviceName}`,
      )
      const url = `${deviceControlConfig.baseUrl}#!action=stream&udid=${encodedUdid}&player=mse&ws=${wsUrl}`

      console.log('设备控制URL（协议自适应）:', {
        currentProtocol: window.location.protocol,
        baseUrl: deviceControlConfig.baseUrl,
        wsProtocol: deviceControlConfig.wsProtocol,
        finalUrl: url,
      })

      this.currentDeviceName = deviceName
      this.currentDeviceUrl = url
      this.showDeviceControlModal = true
    },
    closeDeviceControlModal() {
      this.showDeviceControlModal = false
      this.currentDeviceUrl = ''
    },
    refreshIframe() {
      const iframe = this.$refs.deviceControlFrame
      if (iframe) {
        const currentSrc = iframe.src
        iframe.src = ''
        setTimeout(() => {
          iframe.src = currentSrc
        }, 50)
      }
    },
    async copyToClipboard(text, label) {
      if (!text) {
        this.$message.warning('没有可复制的内容')
        return
      }

      try {
        // 优先使用现代的 Clipboard API
        if (navigator.clipboard && window.isSecureContext) {
          await navigator.clipboard.writeText(text)
        } else {
          // 回退到传统方法
          const input = document.createElement('input')
          input.value = text
          document.body.appendChild(input)
          input.select()
          document.execCommand('copy')
          document.body.removeChild(input)
        }

        // 显示成功提示
        this.$message.success(`${label}已复制到剪贴板`)
      } catch (error) {
        console.error('复制失败:', error)
        this.$message.error(`${label}复制失败，请手动复制`)
      }
    },
  },
  mounted() {
    this.reportId = this.$route.params.id
    this.fetchReportDetail()
  },
  beforeUnmount() {
    window.removeEventListener('resize', this.handleResize)
    if (this.memoryChart) {
      try {
        this.memoryChart.dispose()
      } catch (e) {}
      this.memoryChart = null
    }
  },
}
</script>

<style scoped>
.report-detail-container {
  min-height: calc(100vh - 74px);
  /* background-color: white; */
  width: 100%;
}

.content-wrapper {
  padding: 12px;
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}

.section {
  margin-bottom: 10px;
  padding: 0;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--el-border-color);
  min-height: 28px;
  flex-wrap: wrap;
  gap: 8px;
  width: 100%;
}

.section-title {
  font-size: 15px;
  color: #333;
  margin: 0;
  flex: 0 0 auto;
  margin-right: auto;
  text-align: left;
  font-weight: 600;
}

.memory-chart {
  width: 100%;
  height: 400px;
}

.report-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
  padding: 8px 0;
}

.back-btn {
  margin-right: 12px;
}

.title-container {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}

.report-title {
  margin: 0;
  font-size: 18px;
  color: #303133;
  font-weight: 600;
}

.report-id-container {
  display: flex;
  align-items: center;
  gap: 6px;
}

.report-id {
  font-size: 14px;
  color: #909399;
  font-weight: 400;
  font-family: 'Courier New', monospace;
}

.title-copy-btn {
  width: 18px;
  height: 18px;
  background: rgba(144, 147, 153, 0.1);
}

.title-copy-btn:hover {
  background: rgba(144, 147, 153, 0.2);
}

.title-copy-btn .copy-icon {
  width: 10px;
  height: 10px;
}

.basic-info-layout {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  margin-top: 8px;
}

.info-card {
  overflow: hidden;
}

.primary-info {
  border-left: 3px solid #42b983;
}

.app-info {
  border-left: 3px solid #409eff;
}

.device-info {
  border-left: 3px solid #f39c12;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  /* background: #f8f9fa; */
  border-bottom: 1px solid var(--el-border-color);
}

.card-icon {
  font-size: 16px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-title {
  font-size: 13px;
  font-weight: 600;
  color: #495057;
}

.card-content {
  padding: 0;
}

.info-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 8px;
  gap: 8px;
}

.info-row:last-child {
  margin-bottom: 0;
}

.info-row label {
  font-weight: 500;
  color: #6c757d;
  font-size: 12px;
  min-width: 70px;
  flex-shrink: 0;
}

.info-value-container {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1;
  justify-content: flex-end;
}

.info-value {
  color: #495057;
  font-size: 13px;
  word-break: break-all;
  text-align: right;
}

.info-value.highlight {
  color: #42b983;
  font-weight: 600;
}

.info-value.package {
  color: #409eff;
  font-weight: 500;
}

.info-value.version {
  color: #f39c12;
  font-weight: 500;
}

.info-value.uuid,
.info-value.serial {
  font-family: 'Courier New', monospace;
  font-size: 11px;
  color: #6c757d;
}

/* Element Plus按钮替代了复制按钮，保留布局样式 */

.coverage-layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-top: 6px;
}

.coverage-chart-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 90px;
}

.chart-title {
  font-size: 13px;
  font-weight: 600;
  color: #495057;
  text-align: center;
  margin: 0;
}

.coverage-chart {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.pie-chart-container {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pie-chart {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

.pie-chart-center {
  width: 54px;
  height: 54px;
  /* background: white; */
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

.percentage {
  font-size: 14px;
  font-weight: 700;
  color: #42b983;
  line-height: 1;
}

.label {
  font-size: 10px;
  color: #6c757d;
  margin-top: 2px;
}

.chart-legend {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: #6c757d;
}

.memory-legend-item {
  display: flex;
  align-items: center;
  width: 100%;
}

.memory-legend-item.inactive .legend-name {
  color: #c0c4cc;
}

.legend-name {
  flex: 1;
  user-select: text;
}

.legend-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 8px;
  cursor: pointer;
}

.legend-dot:focus {
  outline: 2px solid #409eff;
  outline-offset: 2px;
}

.legend-avg {
  margin-left: 12px;
  font-size: 11px;
  color: #909399;
  text-align: right;
  white-space: nowrap;
  user-select: text;
}

.memory-legend-item.inactive .legend-avg {
  color: #d3d4d6;
}

.legend-max,
.legend-min {
  margin-left: 12px;
  font-size: 11px;
  color: #909399;
  white-space: nowrap;
  user-select: text;
}

.memory-legend-item.inactive .legend-max,
.memory-legend-item.inactive .legend-min {
  color: #d3d4d6;
}

.legend-color {
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

.legend-color.covered {
  background-color: #42b983;
}

.legend-color.uncovered {
  background-color: #e4e7ed;
}

.table-empty-success {
  color: #67c23a;
  text-align: center;
  padding: 16px 0;
}

.coverage-stats-container {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 90px;
  justify-content: space-around;
}

.coverage-stat-card {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-height: 45px;
  justify-content: center;
}

.stat-icon {
  font-size: 14px;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(66, 185, 131, 0.1);
  border-radius: 50%;
  flex-shrink: 0;
}

.stat-content {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.stat-top-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 2px;
}

.stat-value {
  font-size: 15px;
  font-weight: 700;
  color: #495057;
  margin-bottom: 0;
  flex: 1;
}

.stat-label {
  font-size: 10px;
  color: #6c757d;
  text-align: left;
  margin-left: 2px;
}

.events-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 6px;
  margin-top: 6px;
}

.event-total {
  grid-column: 1 / -1;
  text-align: center;
  margin-bottom: 4px;
  min-height: 70px;
}

.event-total-label {
  font-size: 12px;
  color: #606266;
  margin-bottom: 4px;
}

.event-total-value {
  font-size: 18px;
  font-weight: 600;
  color: #409eff;
}

.event-item {
  text-align: center;
  min-height: 85px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.event-count {
  font-size: 16px;
  font-weight: 600;
  color: #409eff;
  margin-bottom: 4px;
}

.event-label {
  font-size: 13px;
  color: #606266;
  margin-bottom: 3px;
}

.event-percentage {
  font-size: 11px;
  color: #909399;
}

.activities-container {
  margin-top: 6px;
}

.activities-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.activities-section {
  padding: 0;
}

.activities-subtitle {
  font-size: 13px;
  color: #495057;
  margin: 0;
  font-weight: 600;
}

.activities-list {
  max-height: 300px;
  overflow-y: auto;
}

.activity-item {
  padding: 6px 8px;
  /* background-color: #f8f9fa; */
  border-radius: 3px;
  border: 1px solid var(--el-border-color);
  margin-bottom: 6px;
  font-size: 12px;
  color: #495057;
  word-break: break-all;
  transition: background-color 0.2s ease;
}

.activity-item:last-child {
  margin-bottom: 0;
}

.activity-item:hover {
  background-color: rgba(0, 0, 0, 0.02);
}

.empty-message {
  text-align: center;
  padding: 20px;
  color: #909399;
  font-style: italic;
  font-size: 14px;
}

.crashes-container {
  margin-top: 10px;
}

.crashes-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.crash-item {
  padding: 16px;
  /* background-color: #fef0f0; */
  border: 1px solid var(--el-border-color);
  border-radius: 6px;
  text-align: left;
}

.crash-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  flex-wrap: wrap;
  gap: 8px;
}

.crash-title {
  font-size: 14px;
  font-weight: 600;
  color: #f56c6c;
  text-align: left;
}

.crash-time {
  font-size: 12px;
  color: #606266;
  text-align: right;
}

.crash-details {
  margin-bottom: 12px;
  text-align: left;
}

.crash-type {
  padding: 4px 8px;
  background-color: #f56c6c;
  color: white;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 500;
  display: inline-block;
  margin-bottom: 8px;
}

.crash-message {
  font-weight: 500;
  color: #f56c6c;
  word-break: break-all;
  text-align: left;
  line-height: 1.6;
  font-size: 14px;
}

.crash-stack {
  /* background-color: #f5f5f5; */
  padding: 12px;
  border-radius: 4px;
  overflow-x: auto;
  text-align: left;
}

.crash-stack pre {
  margin: 0;
  font-size: 11px;
  color: #666;
  line-height: 1.4;
  white-space: pre-wrap;
  word-wrap: break-word;
  text-align: left;
}

.no-crashes {
  text-align: center;
  padding: 40px 20px;
  /* background-color: #f0f9eb; */
  border: 1px solid var(--el-border-color);
  border-radius: 6px;
}

.no-crashes-icon {
  font-size: 40px;
  color: #67c23a;
  margin-bottom: 16px;
}

.no-crashes-message {
  font-size: 14px;
  color: #67c23a;
  font-weight: 500;
}

.download-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

/* Element Plus按钮替代了下载按钮 */

/* Element Plus v-loading 替代了自定义加载样式 */

.error-message {
  width: 100%;
  padding: 30px;
  /* background-color: #fef0f0; */
  color: #f56c6c;
  border-radius: 6px;
  text-align: center;
  margin: 20px 0;
  font-size: 14px;
}

/* Element Plus按钮替代了重试按钮 */

@media (max-width: 992px) {
  /* 中等屏幕适度减少内边距 */
  .coverage-stat-card :deep(.el-card__body) {
    padding: 6px;
  }

  .event-item :deep(.el-card__body) {
    padding: 5px;
  }

  .basic-info-layout {
    grid-template-columns: 1fr;
  }

  .coverage-layout {
    grid-template-columns: 1fr;
    gap: 8px;
  }

  .coverage-chart-container {
    order: 2;
  }

  .coverage-stats-container {
    order: 1;
  }

  .events-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .activities-columns {
    grid-template-columns: 1fr;
  }

  .crash-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .crash-time {
    text-align: left;
  }

  .section-header {
    justify-content: space-between;
    align-items: center;
    flex-wrap: nowrap;
    gap: 16px;
  }

  .section-title {
    flex: 1;
    margin-right: 16px;
  }

  .download-actions {
    flex-shrink: 0;
  }
}

@media (max-width: 768px) {
  /* 移动端进一步减少卡片内边距 */
  .info-card :deep(.el-card__body) {
    padding: 8px;
  }

  .coverage-chart-container :deep(.el-card__body) {
    padding: 8px;
  }

  .coverage-stat-card :deep(.el-card__body) {
    padding: 6px;
  }

  .event-total :deep(.el-card__body) {
    padding: 6px;
  }

  .event-item :deep(.el-card__body) {
    padding: 4px;
  }

  .activities-section :deep(.el-card__body) {
    padding: 8px;
  }

  .report-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }

  .title-container {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    width: 100%;
  }

  .report-id-container {
    align-self: flex-start;
  }

  .basic-info-layout {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .coverage-stats-container {
    flex-direction: row;
    overflow-x: auto;
    gap: 8px;
  }

  .coverage-stat-card {
    min-width: 150px;
    flex-shrink: 0;
  }

  .events-grid {
    grid-template-columns: 1fr;
  }

  .info-row {
    flex-direction: column;
    gap: 4px;
  }

  .info-row label {
    min-width: auto;
  }

  .info-value-container {
    justify-content: flex-start;
    width: 100%;
  }

  .info-value {
    text-align: left;
  }

  .activities-columns {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  .crash-stack {
    padding: 8px;
  }

  .crash-stack pre {
    font-size: 11px;
    line-height: 1.3;
  }

  .section-header {
    justify-content: space-between;
    align-items: center;
    flex-wrap: nowrap;
    gap: 12px;
  }

  .download-btn {
    padding: 4px 8px;
    font-size: 12px;
  }
}

/* Element Plus Card 内边距定制 */
.info-card :deep(.el-card__body) {
  padding: 16px;
}

.coverage-chart-container :deep(.el-card__body) {
  padding: 16px;
}

.coverage-stat-card :deep(.el-card__body) {
  padding: 16px;
}

.event-total :deep(.el-card__body) {
  padding: 16px;
}

.event-item :deep(.el-card__body) {
  padding: 16px;
}

.activities-section :deep(.el-card__body) {
  padding: 16px;
}

/* Element Plus Dialog 样式定制 */
.device-control-dialog {
  width: 50%;
  max-width: 600px;
}

.dialog-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.device-control-container {
  height: 600px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.device-control-frame {
  width: 100%;
  height: 100%;
  border: none;
}

@media (max-width: 992px) {
  .device-control-dialog {
    width: 70%;
  }

  .device-control-container {
    height: 500px;
  }
}

@media (max-width: 768px) {
  .device-control-dialog {
    width: 90%;
  }

  .device-control-container {
    height: 400px;
  }
}

@media (max-width: 900px) {
  .content-wrapper {
    padding: 8px;
  }

  .basic-info-layout {
    grid-template-columns: 1fr;
    gap: 8px;
  }

  .events-grid {
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 6px;
  }
}
</style> 